#pragma once
#include <iostream>
#include <string>
#include <unistd.h>
#include <vector>
#include <queue>
#include <pthread.h>
#include "task.hpp"

using namespace std;

#define N 5

template<class T>
class ThreadPool{
public:
    ThreadPool(int num = N): _num(num), _threads(num){
        pthread_mutex_init(&_lock, nullptr);
        pthread_cond_init(&_cond, nullptr);
    }

    ~ThreadPool(){
        pthread_mutex_destroy(&_lock);
        pthread_cond_destroy(&_cond);
    }

    void lockQueue(){
        pthread_mutex_lock(&_lock);
    }

    void unlockQueue(){
        pthread_mutex_unlock(&_lock);
    }

    void threadWait(){
        pthread_cond_wait(&_cond, &_lock);
    }

    void threadWakeUp(){
        pthread_cond_signal(&_cond);
    }

    bool empty(){
        return _tasks.empty();
    }

    //在加锁环境中使用，不需要再次加锁
    T popTask(){
        T t = _tasks.front();
        _tasks.pop();
        return t;
    }

    //回调函数
    //类内的成员函数包含this指针，不满足void *outine(void* args)，加static可以消除this
    static void *threadRoutine(void* args){
        //规定当线程退出时自动释放线程资源，被分离的线程不能被join
        pthread_detach(pthread_self());
        ThreadPool<T> *tp = static_cast<ThreadPool<T> *>(args);

        while(1){
            // sleep(1);
            // cout << pthread_self() << " : running" << endl;

            //1.检测有没有任务
            //2.有就处理，没有就等待
            //检测有没有任务的时候是在访问共享资源，必须要加锁

            // -err
            //静态成员函数无法使用非静态的成员
            // pthread_mutex_lock(&_lock);
            // if(_tasks.empty()){

            // }
            // T t = _tasks.front();
            // _tasks.pop();
            // t.run();

            // pthread_mutex_unlock(&_lock);

            tp->lockQueue();
            //任务为空就等待
            while(tp->empty()){
                tp->threadWait();
            }
            //从共享区拿到私有区
            T t = tp->popTask();
            // //处理任务不应该在临界区处理
            // t.run(); // err
            t();
            cout << "thread handler done, result : " << t.formatArg() << t.formatRes() << endl;
            tp->unlockQueue();
        }
    }

    void init(){

    }

    void start(){
        for (int i = 0; i < _num;i++){
            pthread_create(&_threads[i], nullptr, threadRoutine, this);
        }
    }

    void pushTask(const T& t){
        lockQueue();
        _tasks.push(t);
        //添加一个任务之后唤醒一个等待中的线程
        threadWakeUp();
        unlockQueue();
    }



private:
    vector<pthread_t> _threads; //线程池
    int _num;

    queue<T> _tasks;            //任务队列
    pthread_mutex_t _lock;
    pthread_cond_t _cond;        //条件变量，线程等待的地方
};